#region Microsoft Public License
/*
 * (c) Copyright Chenjun Wu. http://utablesdk.codeplex.com
 * 
 * This source is subject to the Microsoft Public License (Ms-PL).
 * Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details.
 * All other rights reserved.
 */
#endregion

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Shapes;
using UTable.Input;
using UTable.Input.MultiTouch;
using UTable.Input.Text;
using UTable.Objects.Handlers;


namespace UTable.Objects.Controls
{
    public class UTextBox: TextBox, IControl, IControlDisposable
    {
        #region Private Fields

		private Rectangle _caret;
        
        #endregion

        #region Private Methods

		void UTextBox_InputReceived(InputEventArgs args)
		{
			if (args is TextInputEventArgs)
				OnTextDetected(args as TextInputEventArgs);
			args.Handled = true;
		}

		void handler_OneFingerUp(List<FingerPoint> fingers)
		{
			Point p = fingers[0].Position;
			if (p.X >= 0 && p.X <= this.Width && p.Y >= 0 && p.Y <= this.Height)
			{
				UTableHelper.TextInputManager.RequestTextInput(this);
				CaretShown = true; 
			}
		}

		void handler_OneFingerDown(List<FingerPoint> fingers)
		{
			this.CaptureFinger(fingers[0].ID);
			// if (CaretShown)
			{
				SetCaretPosition(fingers[0].Position);
			}
		}

		void handler_OneFingerMove(List<FingerPoint> oFigners, List<FingerPoint> nFingers)
		{
			Point p = nFingers[0].Position;
			if (CaretShown)
			{
				SetCaretPosition(p);
			}
		}

		private void UTextBox_TextChanged(object sender, TextChangedEventArgs e)
		{

		}

		private void SetCaretPosition(Point p)
		{
			int index = this.GetCharacterIndexFromPoint(p, true);
			if (index == this.Text.Length - 1)
				index++;
			this.CaretIndex = index;

            int line = GetLineIndexFromCharacterIndex(index);
            if (line < GetFirstVisibleLineIndex())
            {
                ScrollToLine(line);
            }
            else if (line > GetLastVisibleLineIndex())
            {
                ScrollToLine(line);
            }
		}

		private void UTextBox_Loaded(object sender, RoutedEventArgs e)
		{
			this.CaretIndex = this.Text.Length;
			OnShowCaretChanged(null, null);
		}

		private void OnCaretIndexChanged(object sender, EventArgs e)
		{
			base.CaretIndex = this.CaretIndex;
			SetCaretPosition();

            int line = GetLineIndexFromCharacterIndex(this.CaretIndex);
            if (line < GetFirstVisibleLineIndex())
            {
                ScrollToLine(line);
            }
            else if (line > GetLastVisibleLineIndex())
            {
                ScrollToLine(line);
            }
		}

		private void OnShowCaretChanged(object sender, EventArgs e)
		{
			if (CaretShown)
			{
				_caret.Visibility = Visibility.Visible;
			}
			else
			{
				_caret.Visibility = Visibility.Hidden;
			}
		}

		private void SetCaretPosition()
		{
			Rect rect = this.GetRectFromCharacterIndex(this.CaretIndex);
			Canvas.SetLeft(this._caret, rect.Left - 2);
			Canvas.SetTop(this._caret, rect.Top);
		}

		private void OnTextDetected(TextInputEventArgs textArgs)
		{
			if (textArgs.ControlCommand != ControlCommand.None)
			{
				switch (textArgs.ControlCommand)
				{
					case ControlCommand.Back:
						if (this.Text.Length > 0)
						{
							this.Text = this.Text.Remove(this.CaretIndex - 1, 1);
							this.CaretIndex -= 1;
						}
						break;
					case ControlCommand.Clear:
						this.Text = "";
						this.CaretIndex = 0;
						break;
					case ControlCommand.Escape:
						CaretShown = false;
						break;
				}
				return;
			}
			if (textArgs.Text != "")
			{
				this.Text = this.Text.Insert(this.CaretIndex, textArgs.Text);
				this.CaretIndex += textArgs.Text.Length;

				/*
				System.Windows.Input.KeyEventArgs e = new System.Windows.Input.KeyEventArgs(
					System.Windows.Input.Keyboard.PrimaryDevice, (UTableHelper.CurrentVisualTree as UObject).PresentationSource,
								  0, System.Windows.Input.Key.A);
				e.RoutedEvent = System.Windows.Input.Keyboard.KeyDownEvent;
				this.RaiseEvent(e);*/

				
				// this.OnTextInput(new System.Windows.Input.TextCompositionEventArgs(System.Windows.Input.InputManager.Current.PrimaryKeyboardDevice, new System.Windows.Input.TextComposition(System.Windows.Input.InputManager.Current, this, textArgs.Text)));
				return;
			}
		}

		public override void OnApplyTemplate()
		{
			base.OnApplyTemplate();
			this._caret = this.GetTemplateChild("PART_Caret") as Rectangle;
		}


        #endregion

        #region Properties

        public new int CaretIndex
        {
            get { return (int)GetValue(CaretIndexProperty); }
            set { SetValue(CaretIndexProperty, value); }
        }

        public static readonly DependencyProperty CaretIndexProperty =
            DependencyProperty.Register("CaretIndex", typeof(int), typeof(UTextBox), new UIPropertyMetadata(0));

        public bool CaretShown
        {
            get { return (bool)GetValue(CaretShownProperty); }
            set { SetValue(CaretShownProperty, value); }
        }

        public static readonly DependencyProperty CaretShownProperty =
            DependencyProperty.Register("CaretShown", typeof(bool), typeof(UTextBox), new UIPropertyMetadata(false));

        #endregion

        #region Constructors

        static UTextBox()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(UTextBox), new FrameworkPropertyMetadata(typeof(UTextBox)));
        }

        public UTextBox()
        {
            InitializeIControlPart();
            OneFingerHandler handler = new OneFingerHandler();
            handler.OneFingerDown += new FingersDownEventHandler(handler_OneFingerDown);
            handler.OneFingerUp += new FingersUpEventHandler(handler_OneFingerUp);
            handler.OneFingerMove += new FingersMoveEventHandler(handler_OneFingerMove);
            MultiTouchProcessor.Handlers.Add(handler);
            this.InputReceived += new InputEventHandler(UTextBox_InputReceived);
            this.TextChanged += new TextChangedEventHandler(UTextBox_TextChanged);
            this.Loaded += new RoutedEventHandler(UTextBox_Loaded);

            DependencyPropertyDescriptor.FromProperty(UTextBox.CaretIndexProperty,
                    typeof(UTextBox)).AddValueChanged(this, new EventHandler(OnCaretIndexChanged));
            DependencyPropertyDescriptor.FromProperty(UTextBox.CaretShownProperty,
                    typeof(UTextBox)).AddValueChanged(this, new EventHandler(OnShowCaretChanged));
        }

        #endregion

		#region IControl Implementation
		
		#region Private Fields

        private ControlBaseImpl _impl;

        #endregion

		#region Private Methods

		private void InitializeIControlPart()
        {
			_impl = new ControlBaseImpl(this);
            _impl.GotFingerCapture += new UTable.Input.MultiTouch.FingerEventHandler(_impl_GotFingerCapture);
            _impl.LostFingerCapture += new UTable.Input.MultiTouch.FingerEventHandler(_impl_LostFingerCapture);
			this.InputReceived += new UTable.Input.InputEventHandler(_impl_InputReceived);
        }

        void _impl_InputReceived(UTable.Input.InputEventArgs args)
        {
			if (args is UTable.Input.MultiTouch.MultiTouchEventArgs)
				MultiTouchProcessor.RaiseMultiTouchEvent(args as UTable.Input.MultiTouch.MultiTouchEventArgs);
        }

        void _impl_LostFingerCapture(object sender, UTable.Input.MultiTouch.FingerEventArgs args)
        {
            if (LostFingerCapture != null)
                LostFingerCapture(sender, args);
        }

        void _impl_GotFingerCapture(object sender, UTable.Input.MultiTouch.FingerEventArgs args)
        {
            if (GotFingerCapture != null)
                GotFingerCapture(sender, args);
        }

        #endregion

        #region IControl Members

        public UTable.Objects.Controls.ControlInfo Info
        {
            get { return _impl.Info; }
        }
		
		public UTable.Objects.Handlers.MultiTouchProcessor MultiTouchProcessor 
		{ 
			get { return _impl.MultiTouchProcessor; } 
		}

        public void DisposeControl()
        {
            DependencyPropertyDescriptor.FromProperty(UTextBox.CaretIndexProperty,
                    typeof(UTextBox)).RemoveValueChanged(this, new EventHandler(OnCaretIndexChanged));
            DependencyPropertyDescriptor.FromProperty(UTextBox.CaretShownProperty,
                    typeof(UTextBox)).RemoveValueChanged(this, new EventHandler(OnShowCaretChanged));
        }

        #endregion

        #region IVisualNode Members

        public String ID
        {
            get { return _impl.ID; }
        }

        public new double Width
        {
            get { return _impl.Width; }
            set { _impl.Width = value; }
        }

        public new double Height
        {
            get { return _impl.Height; }
            set { _impl.Height = value; }
        }

        public new bool IsHitTestVisible
        {
            get { return _impl.IsHitTestVisible; }
            set { _impl.IsHitTestVisible = value; }
        }

        #endregion

        #region IInputNode Members

        public void RaiseEvent(UTable.Input.InputEventArgs e)
        {
            if (InputReceived != null)
            {
                InputReceived(e);
            }
            OnInputReceived(e);
        }

        public virtual void OnInputReceived(UTable.Input.InputEventArgs args)
        {
            _impl.OnInputReceived(args);
        }

        public bool CaptureFinger(int fingerId)
        {
            return _impl.CaptureFinger(fingerId);
        }

        public bool UncaptureFinger(int fingerId)
        {
            return _impl.UncaptureFinger(fingerId);
        }

        public event UTable.Input.MultiTouch.FingerEventHandler GotFingerCapture;

        public event UTable.Input.MultiTouch.FingerEventHandler LostFingerCapture;

        public event UTable.Input.InputEventHandler InputReceived;

        #endregion
        #endregion
    }
}
